﻿using UnityEngine;
using System.Collections;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System.Text;
using LitJson;
using SevenZip.Compression.LZMA;
using System;


/*==============    
 * Creater:LR
 * Date:2015.8.12
 * 
 *==============
 */
enum FilenameExtension
{
    unity3d = 1,
    assetbundle = 2
}
public class AssetBunldeWindow : ScriptableWizard
{
    bool Encryption;
    // static Dictionary<string, bool> optionDic = new Dictionary<string, bool>();
    SortedList SortDic = new SortedList();
    BuildTarget bt;

    string[] status = { "Bulid Together", "Bulid Independent", "Bulid Scene", "filename extension", "ExportJson", "CompressFileLZMA" };
    static public string atlasName;
    string BunldeName = "";
    string Path = "";
    string[] levels = new string[1];
    CodeProgress m_CodeProgress = null;//进度;
    float slider = 0;
    [MenuItem("Custom Editor/My AssetBundle/Create AllSelectedAssetBunldes #&i")]

    static void SetBunldeName()
    {
        ScriptableWizard.DisplayWizard<AssetBunldeWindow>("Create AssetBundle");
    }
    enum Platform
    {
        StandaloneWindows,
        StandaloneOSXIntel,
        Android,
        iPhone
    }
    enum FileExtension
    {
        unity3d = 0,
        assetbundle = 1
    }
    FilenameExtension m_op = FilenameExtension.assetbundle;
    static Platform m_platform = Platform.StandaloneWindows;
    void Awake()
    {
        if (SortDic.Count <= 0)
        {
            SortDic.Add("showOption1", true);
            SortDic.Add("showOption2", true);
            SortDic.Add("showOption3", true);
            SortDic.Add("showOption4", true);
            SortDic.Add("showOption5", true);
        }
        m_CodeProgress = new CodeProgress(SetProgressPercent);
    }
    private float m_Percent = 0f;


    static void Save()
    {
        EditorPrefs.SetInt("Plaform", (int)m_platform);
    }
    static void Load()
    {
        EditorPrefs.GetInt("Platform", 0);
    }
    void SelectPlatform()
    {
        GUILayout.BeginHorizontal();
        Platform pf = (Platform)EditorGUILayout.EnumPopup("Platform", m_platform, GUILayout.Width(300f));
        GUILayout.Space(20f);
        GUILayout.Label("Select a Platform to use");
        GUILayout.EndHorizontal();
        if (m_platform != pf) { m_platform = pf; Save(); }
        bt = BuildTarget.StandaloneWindows;
        switch (m_platform)
        {
            case Platform.StandaloneWindows:
                bt = BuildTarget.StandaloneWindows;
                break;
            case Platform.Android:
                bt = BuildTarget.Android;
                break;
            case Platform.iPhone:
                bt = BuildTarget.iPhone;
                break;
            case Platform.StandaloneOSXIntel:
                bt = BuildTarget.StandaloneOSXIntel;
                break;
        }

    }
    void GetEncryption()
    {
        GUILayout.BeginHorizontal();
        Encryption = GUILayout.Toggle(Encryption, "Encryption");
        //Debug.Log(Encryption);
        GUILayout.EndHorizontal();
    }
    void ExportJson()
    {

        //string filepath = Application.dataPath + @"/StreamingAssets/json.txt";
        string filepath = EditorUtility.SaveFilePanel("Save Json", null, null, "txt");
        FileInfo t = new FileInfo(filepath);
        if (File.Exists(filepath))
        {
            File.Delete(filepath);
        }
        StreamWriter sw = t.CreateText();
        StringBuilder sb = new StringBuilder();
        JsonWriter writer = new JsonWriter(sb);
        writer.WriteObjectStart();
        writer.WritePropertyName("GameObjects");
        writer.WriteArrayStart();

        foreach (UnityEditor.EditorBuildSettingsScene S in UnityEditor.EditorBuildSettings.scenes)
        {
            if (S.enabled)
            {
                string name = S.path;
                Debug.Log(name);
                EditorApplication.OpenScene(name);
                writer.WriteObjectStart();
                writer.WritePropertyName("scenes");
                writer.WriteArrayStart();
                writer.WriteObjectStart();
                writer.WritePropertyName("name");
                writer.Write(name);
                writer.WritePropertyName("gameObject");
                writer.WriteArrayStart();

                foreach (GameObject obj in UnityEngine.Object.FindObjectsOfType(typeof(GameObject)))
                {
                    if (obj.transform.parent == null)
                    {
                        writer.WriteObjectStart();
                        writer.WritePropertyName("name");
                        writer.Write(obj.name);

                        writer.WritePropertyName("position");
                        writer.WriteArrayStart();
                        writer.WriteObjectStart();
                        writer.WritePropertyName("x");
                        writer.Write(obj.transform.position.x.ToString("F2"));
                        writer.WritePropertyName("y");
                        writer.Write(obj.transform.position.y.ToString("F2"));
                        writer.WritePropertyName("z");
                        writer.Write(obj.transform.position.z.ToString("F2"));
                        writer.WriteObjectEnd();
                        writer.WriteArrayEnd();

                        writer.WritePropertyName("rotation");
                        writer.WriteArrayStart();
                        writer.WriteObjectStart();
                        writer.WritePropertyName("x");
                        writer.Write(obj.transform.rotation.eulerAngles.x.ToString("F2"));
                        writer.WritePropertyName("y");
                        writer.Write(obj.transform.rotation.eulerAngles.y.ToString("F2"));
                        writer.WritePropertyName("z");
                        writer.Write(obj.transform.rotation.eulerAngles.z.ToString("F2"));
                        writer.WriteObjectEnd();
                        writer.WriteArrayEnd();

                        writer.WritePropertyName("scale");
                        writer.WriteArrayStart();
                        writer.WriteObjectStart();
                        writer.WritePropertyName("x");
                        writer.Write(obj.transform.localScale.x.ToString("F2"));
                        writer.WritePropertyName("y");
                        writer.Write(obj.transform.localScale.y.ToString("F2"));
                        writer.WritePropertyName("z");
                        writer.Write(obj.transform.localScale.z.ToString("F2"));
                        writer.WriteObjectEnd();
                        writer.WriteArrayEnd();

                        writer.WriteObjectEnd();
                    }
                }

                writer.WriteArrayEnd();
                writer.WriteObjectEnd();
                writer.WriteArrayEnd();
                writer.WriteObjectEnd();
            }
        }
        writer.WriteArrayEnd();
        writer.WriteObjectEnd();


        sw.WriteLine(sb.ToString());
        sw.Close();
        sw.Dispose();
        AssetDatabase.Refresh();

    }
    void CompressFileLZMA(string inFile, string outFile)
    {
        SevenZip.Compression.LZMA.Encoder coder = new SevenZip.Compression.LZMA.Encoder();

        FileStream input = new FileStream(inFile, FileMode.Open);
        FileStream output = new FileStream(outFile, FileMode.Create);
        coder.WriteCoderProperties(output);
        output.Write(BitConverter.GetBytes(input.Length), 0, 8);
        coder.Code(input, output, input.Length, -1, null);
        output.Flush();
        output.Close();
        input.Flush();
        input.Close();
        Debug.Log("Compress successfully!");
        AssetDatabase.Refresh();
    }
    void SelectFilenameExtension(FilenameExtension op)
    {
        switch (op)
        {
            case FilenameExtension.assetbundle:
                string ss;
                break;
            case FilenameExtension.unity3d:
                string aa;
                break;
        }
    }
    void BulidTogether()
    {

        UnityEngine.Object[] SelectedAsset = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.DeepAssets);

        if (Selection.objects.Length > 0)
        {
            string targetPath = Application.dataPath + "/StreamingAssets/" + BunldeName + ".assetbundle";
            if (BuildPipeline.BuildAssetBundle(null, SelectedAsset, targetPath, BuildAssetBundleOptions.CollectDependencies, bt))
            {
                Debug.Log(BunldeName + " is  Packed successfully!");
                if (Encryption)
                {
                    FileStream fs = new FileStream(targetPath, FileMode.Open, FileAccess.ReadWrite);
                    byte[] buff = new byte[fs.Length + 3];
                    fs.Read(buff, 0, (int)fs.Length);
                    buff[buff.Length - 1] = 0;
                    buff[buff.Length - 2] = 1;
                    buff[buff.Length - 3] = 2;
                    fs.Close();
                    File.Delete(targetPath);

                    string BinPath = targetPath.Substring(0, targetPath.LastIndexOf('.')) + ".dat";
                    FileStream cfs = new FileStream(BinPath, FileMode.Create);
                    cfs.Write(buff, 0, buff.Length);
                    buff = null;
                    cfs.Close();
                }
            }
            else
            {
                Debug.Log(BunldeName + "  is  Failed to Pack!");
            }
        }
        else
        {
            Debug.Log("Please select at least one item!");
        }

        AssetDatabase.Refresh();
    }
    void BulidIndependent()
    {

        UnityEngine.Object[] SelectedAsset = Selection.GetFiltered(typeof(UnityEngine.Object), SelectionMode.DeepAssets);

        if (Selection.objects.Length > 0)
        {
            foreach (UnityEngine.Object obj in SelectedAsset)
            {
                string targetPath = Application.dataPath + "/StreamingAssets/" + obj.name + ".assetbundle";
                if (BuildPipeline.BuildAssetBundle(obj, null, targetPath, BuildAssetBundleOptions.CollectDependencies, bt))
                {
                    Debug.Log(obj.name + "Packed successfully!");
                    if (Encryption)
                    {
                        FileStream fs = new FileStream(targetPath, FileMode.Open, FileAccess.ReadWrite);
                        byte[] buff = new byte[fs.Length + 3];
                        fs.Read(buff, 0, (int)fs.Length);
                        buff[buff.Length - 1] = 0;
                        buff[buff.Length - 2] = 1;
                        buff[buff.Length - 3] = 2;
                        fs.Close();
                        File.Delete(targetPath);

                        string BinPath = targetPath.Substring(0, targetPath.LastIndexOf('.')) + ".assetbundle";
                        FileStream cfs = new FileStream(BinPath, FileMode.Create);
                        cfs.Write(buff, 0, buff.Length);
                        buff = null;
                        cfs.Close();
                    }

                }
                else
                {
                    Debug.Log(obj.name + "Failed to Pack!");
                }
            }

        }
        else
        {
            Debug.Log("Please select at least one item!");
        }
        //刷新编辑器
        AssetDatabase.Refresh();

    }
    void BulidScene()
    {
        Caching.CleanCache();
        string Path = EditorUtility.SaveFilePanel("OutputScene", null, null, "unity3d");

        Debug.Log(Path);
        string[] levels = { EditorUtility.OpenFilePanel("InputScene", null, "unity") };
        Debug.Log(levels[0]);
        if (!string.IsNullOrEmpty(levels[0]))
        {
            BuildPipeline.BuildPlayer(levels, Path, bt, BuildOptions.BuildAdditionalStreamedScenes);
            AssetDatabase.Refresh();
        }


    }
    /// <summary>
    /// 压缩进度
    /// </summary>
    /// <param name="fileSize"></param>
    /// <param name="processSize"></param>
    void SetProgressPercent(Int64 fileSize, Int64 processSize)
    {
        m_Percent = (float)processSize / fileSize;
    }
    void Update()
    {

        if (m_Percent > 0f)
        {

            slider = m_Percent;
           
            if (m_Percent == 1f)
            {
                Debug.Log("m_Percent==1f");
                m_Percent = 0f;
                AssetDatabase.Refresh();
            }
        }
    }
    void OnGUI()
    {
       
        SelectPlatform();
        GetEncryption();
        #region Bulid Together
        GUILayout.Label("", GUILayout.Height(10f));
        SortDic.SetByIndex(0, EditorGUILayout.Foldout((bool)SortDic.GetByIndex(0), status[0]));
        if ((bool)SortDic.GetByIndex(0))
        {
            for (int i = 0; i < SortDic.Count; i++)
            {
                if (i != 0)
                {
                    SortDic.SetByIndex(i, false);
                }
            }
            bool Create = false;
            // EditorGUIUtility.LookLikeControls(80f);
            string newItemName = EditorGUILayout.TextField("Bunlde Name:", BunldeName);
            GUILayout.BeginVertical();
            m_op = (FilenameExtension)EditorGUILayout.EnumPopup("filename extension:", m_op);
            GUILayout.EndVertical();
            SelectFilenameExtension(m_op);
            //  NGUIEditorTools.DrawSeparator();
            if (GUI.changed || newItemName != BunldeName)
            {
                BunldeName = newItemName;
            }
            if (newItemName != "")
            {
                // GUI.backgroundColor = Color.green;

                GUILayout.Label("     ", GUILayout.Height(10f));
                GUILayout.Label("1.Input your BundleName and Select a file suffux to create from popuplist");
                GUILayout.Label("2.Remenber to get selection in Project ");
                GUILayout.Label("3.Click button and this will pack all of the SelectedAsset in a assetbundle!");
                GUILayout.Label("      ", GUILayout.Height(10f));
                Create = GUILayout.Button("Create Together", GUILayout.Width(150f), GUILayout.Height(30f));

            }
            if (Create)
            {
                BulidTogether();
            }
        }
        #endregion

        #region Bulid Independent
        SortDic.SetByIndex(1, EditorGUILayout.Foldout((bool)SortDic.GetByIndex(1), status[1]));
        if ((bool)SortDic.GetByIndex(1))
        {
            for (int i = 0; i < SortDic.Count; i++)
            {
                if (i != 1)
                {
                    SortDic.SetByIndex(i, false);
                }
            }
            GUILayout.Label("     ", GUILayout.Height(10f));
            GUILayout.Label("1.you don't have to input your bundleName that depends on your fileName");
            GUILayout.Label("2.Remenber to get selection in Project ");
            GUILayout.Label("3.Click button and this will pack all of the SelectedAsset in different assetbundles!");
            GUILayout.Label("      ", GUILayout.Height(10f));
            bool Create2 = false;
            Create2 = GUILayout.Button("Create Independent", GUILayout.Width(150f), GUILayout.Height(30f));
            if (Create2)
            {
                BulidIndependent();
            }
        }
        #endregion

        #region Bulid Scene
        SortDic.SetByIndex(2, EditorGUILayout.Foldout((bool)SortDic.GetByIndex(2), status[2]));
        if ((bool)SortDic.GetByIndex(2))
        {
            for (int i = 0; i < SortDic.Count; i++)
            {
                if (i != 2)
                {
                    SortDic.SetByIndex(i, false);
                }
            }

            GUILayout.Space(20f);
            GUILayout.Label(" Scene to be Created of FilePath");
            bool Create3 = false;

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.TextField("InputScenePath", Path);

            bool InputScene = GUILayout.Button("Save", GUILayout.Width(50f));
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.TextField("SelectScenePath", levels[0]);
            bool SelectScene = GUILayout.Button("Open", GUILayout.Width(50f));
            EditorGUILayout.EndHorizontal();
            if (InputScene)
            {
                Path = EditorUtility.SaveFilePanel("OutputScene", null, null, "unity3d");
            }

            if (SelectScene)
            {
                levels[0] = EditorUtility.OpenFilePanel("InputScene", null, "unity");
            }
            Create3 = GUILayout.Button("Create Scene", GUILayout.Width(150f), GUILayout.Height(30f));
            if (Create3)
            {
                Debug.Log("Create3");
                Caching.CleanCache();

                Debug.Log(Path);

                Debug.Log(levels[0]);
                if (!string.IsNullOrEmpty(levels[0]) && !string.IsNullOrEmpty(Path))
                {
                    BuildPipeline.BuildPlayer(levels, Path, bt, BuildOptions.BuildAdditionalStreamedScenes);
                    AssetDatabase.Refresh();
                }
            }


        }
        #endregion

        #region ExportDataBase
        SortDic.SetByIndex(3, EditorGUILayout.Foldout((bool)SortDic.GetByIndex(3), status[4]));
        if ((bool)SortDic.GetByIndex(3))
        {
            for (int i = 0; i < SortDic.Count; i++)
            {
                if (i != 3)
                {
                    SortDic.SetByIndex(i, false);
                }
            }
            GUILayout.Space(10f);
            GUILayout.Label(" You must exit play mode or else it's defeated!");
            GUILayout.Space(10f);

            bool Creat4 = GUILayout.Button("ExportJson", GUILayout.Width(150f), GUILayout.Height(30f));
            if (Creat4)
            {
                ExportJson();
            }
        }
        #endregion

        #region CompressFileLZMA
        SortDic.SetByIndex(4, EditorGUILayout.Foldout((bool)SortDic.GetByIndex(4), status[5]));
        if ((bool)SortDic.GetByIndex(4))
        {
            for (int i = 0; i < SortDic.Count; i++)
            {
                if (i != 4)
                {
                    SortDic.SetByIndex(i, false);
                }
            }
            GUILayout.HorizontalSlider(slider, 0, 1);

            bool Create5 = GUILayout.Button("CompressFile", GUILayout.Width(150f), GUILayout.Height(30f));
            if (Create5)
            {
                string inFile = EditorUtility.OpenFilePanel("InFile", Application.dataPath + "/StreamingAssets", null);
                string folder = Application.persistentDataPath + "/ZIP";
                if (!Directory.Exists(folder))
                {
                    Directory.CreateDirectory(folder);
                }
                string outFile = EditorUtility.SaveFilePanel("OutFile", folder, null, "zip");
                if (!string.IsNullOrEmpty(outFile) && !string.IsNullOrEmpty(inFile))
                {

                    try
                    {
                        //CompressFileLZMA(inFile, outFile);
                        LZMAHelper.Compress(inFile, outFile, m_CodeProgress);
                        
                    }
                    catch (Exception ex)
                    {
                        Debug.Log(ex);
                    }
                }
            }
        }
        #endregion

    }
}
